// 本程序是C语言的指令过滤器，用于过滤出除指令外无用的数据，同时对指令进行相应处理。
#include "IF_InstructionFilter.h"
#include <stdint.h>

/***************************************************************************************************
* 宏定义
*
****************************************************************************************************/
#ifndef NULL
#define NULL                    ((void *)0)
#endif

/***************************************************************************************************
* 内部数据类型定义
*
****************************************************************************************************/


/***************************************************************************************************
* 变量定义
*
****************************************************************************************************/


/***************************************************************************************************
* 函数声明
*
****************************************************************************************************/


/***************************************************************************************************
* 函数原型
*
****************************************************************************************************/
//*****************************************************************************
//
//! 用于标识符自加，内部加入了防止超出上限的处理
//!
//! param:  IndexValue 要自加的值
//!
//!
//! return: 返回自加后的值
//
//*****************************************************************************
static uint8_t IndexAdd(uint8_t IndexValue)
{
    IndexValue++;
    if(IndexValue >= IF_BUFF_SIZE)
        IndexValue = 0;
    return IndexValue;
}
//*****************************************************************************
//
//! 用于标识符自减，内部加入了防止超出下限的处理
//!
//! param:  IndexValue 要自减的值
//!
//!
//! return: 返回自减后的值
//
//*****************************************************************************
// static uint8_t IndexDec(uint8_t IndexValue)
// {
//     if(0 == IndexValue)
//         IndexValue = IF_BUFF_SIZE-1;
//     else
//         IndexValue--;
//     return IndexValue;
// }
//*****************************************************************************
//
//! 复位指令集合的参数到初始状态，将TargetInstruction指令结构复位到初始状态
//!
//! param: StartValue 设置的匹配起点
//!
//!
//! return: 无
//
//*****************************************************************************
static void ResetTargetInstruction(CmdWindow *WindowIden,uint8_t StartValue)
{
    uint8_t i;
    for(i=0;i<WindowIden->CmdLen;i++)
    {
        WindowIden->CMDIndex[i].START = StartValue;//设置起始点
        WindowIden->CMDIndex[i].MACTH = 0;//清零匹配个数
    }
}

//*****************************************************************************
//
//! 更新指令过滤器窗口,左值，为当前指令中的最小值。
//!
//! param: 空
//!
//! return: 空
//
//*****************************************************************************
static void UpdateWindow(CmdWindow *WindowIden)
{
    uint8_t i,Min;
    Min = WindowIden->CMDIndex[0].START;
    for(i=0;i<WindowIden->CmdLen;i++)
    {
        if(Min > WindowIden->CMDIndex[i].START)
        {
            Min = WindowIden->CMDIndex[i].START;
        }
    }
    WindowIden->START = Min;//更新窗口最小值。
}
//*****************************************************************************
//
//! 指令过滤器处理函数
//!
//! param: WindowIden 指令窗口指针
//!         Data 要过滤的数据
//!
//! return: 空
//
//*****************************************************************************
uint8_t IF_InstructionFilter(CmdWindow *WindowIden,uint8_t Data)
{
    uint8_t i,j;
    uint8_t CMDFilterFlag = 1;//标志当前是否允许指令过滤器运行
    uint8_t FunFlag = 1;
    
    if (WindowIden->Fun != WindowIden->CmdLen)//判断当前有没有响应函数需要运行
    {
        j = WindowIden->Fun;
        //先进行超时判断
        if( WindowIden->CMD[j].Timerout != 0 &&
            IF_GET_SYS_TIMER - WindowIden->Timer > WindowIden->CMD[j].Timerout)
        {//等待数据超时
            WindowIden->Fun = WindowIden->CmdLen;//清除响应函数。下轮数据，指令过滤器可以进行处理。
            CMDFilterFlag = 1;//可以继续运行指令处理器
            for(i=0;i<WindowIden->CMD[j].Len;i++)
            {
                IF_WriteData(WindowIden,WindowIden->CMD[j].P[i]);
            }
        }
        else
        {
            //响应函数处理
            FunFlag = WindowIden->CMD[j].Fun(Data, POSITION_REC_CALL);//获取响应函数的处理结果
        if (NO_DEAL_WITH == FunFlag) //【未处理】
        {
	    WindowIden->Fun = WindowIden->CmdLen;//清除响应函数。下轮数据，指令过滤器可以进行处理。
            CMDFilterFlag = 1;//可以继续运行指令处理器
        }
        else if (DEAL_WITH == FunFlag)//【正在处理】
        {
            //响应函数还有数据未捕获完。下个数据将还会是处理数据
            CMDFilterFlag = 0;//数据已被拦截，指令处理器，无权对数据进行处理。
        }
        else if (DEAL_WITH_END == FunFlag)//【处理结束】
        {
                WindowIden->Fun = WindowIden->CmdLen;//清除响应函数。下轮数据，指令过滤器可以进行处理。
            CMDFilterFlag = 0;//数据已被拦截。指令过滤器，无权对数据进行处理。
        }
    }
        WindowIden->Timer = IF_GET_SYS_TIMER;
    }
    if(1 == CMDFilterFlag)//当前数据需要进行指令过滤
    {
        //先进行超时判断
        if(WindowIden->WRITE > WindowIden->START && //判断指令过滤器是否在工作
            IF_GET_SYS_TIMER - WindowIden->Timer > IF_TIMEROUT)//判断是否超时
        {//等待数据超时，重置过滤窗口
            //将每个指令的匹配起始地址，设置为写入地址
            ResetTargetInstruction(WindowIden,WindowIden->WRITE);
            //设置过滤窗口的起点。
            WindowIden->START = WindowIden->WRITE;
        }
        WindowIden->Timer = IF_GET_SYS_TIMER;


        WindowIden->DataWindow[WindowIden->WRITE] = Data;//保存当前数据到指令过滤处理窗口中
        WindowIden->DataWindowNum++;
        for(i=0;i<WindowIden->CmdLen;i++)//从第一条指令循环到最后一条
        {
            j = WindowIden->CMDIndex[i].MACTH;        //取当前指令的匹配进度
            if(WindowIden->CMD[i].P[j] == Data)  
            {//当前指令当前位和当前数据匹配
                WindowIden->CMDIndex[i].MACTH++;
                if(WindowIden->CMDIndex[i].MACTH == WindowIden->CMD[i].Len)//当前指令完全匹配
                {
                    // 带参数的函数
                    if(WindowIden->CMD[i].HaveParam == 1)
                    {
                        WindowIden->Fun = i;
                    }
                    else
                    {  // 不带参数的函数立即处理
                        WindowIden->Fun = WindowIden->CmdLen;
                    }

                    // 收到指令立即调用 或者 是不带参数的函数
                    if(WindowIden->CMD[i].CmdCallFun == 1 || WindowIden->CMD[i].HaveParam == 0)
                    {
                        WindowIden->CMD[i].Fun(0x00, POSITION_CMD_CALL);
                    }
                    //数据个数扣除已响应指令的长度
                    WindowIden->DataWindowNum = WindowIden->DataWindowNum - WindowIden->CMD[i].Len;
                    //将每个指令的匹配起始地址，设置为当前指令的起始地址
                    ResetTargetInstruction(WindowIden,WindowIden->CMDIndex[i].START);
                    //设置过滤窗口的终点。设置当前的写入地址。
                    WindowIden->WRITE = WindowIden->CMDIndex[i].START;
                    //设置过滤窗口的起点。
                    WindowIden->START = WindowIden->CMDIndex[i].START;
                }
            }
            else
            {//不匹配
                if(WindowIden->CMD[i].P[0]==Data)//判断与当前指令第一位指令码是否一致
                {
                    WindowIden->CMDIndex[i].MACTH = 1; //匹配数置1
                    WindowIden->CMDIndex[i].START = WindowIden->WRITE;//匹配起点设定为当前位
                }
                else
                {
                    WindowIden->CMDIndex[i].MACTH = 0; //匹配数置1
                    WindowIden->CMDIndex[i].START = IndexAdd(WindowIden->WRITE);//匹配起点设定为当前位
                }
            }
        }
        WindowIden->WRITE = IndexAdd(WindowIden->WRITE);

        while(  WindowIden->DataWindowNum >0 && //数据窗口中存有数据
                WindowIden->WRITE == WindowIden->READ &&     //当数据存储超出上限
                WindowIden->MaxFun != NULL )//超出上限函数不为空
        {
            WindowIden->MaxFun(WindowIden->DataWindow[WindowIden->READ]);
            WindowIden->READ = IndexAdd(WindowIden->READ);
        }
        UpdateWindow(WindowIden);//更新指令过滤窗口的起点
    }
    return IF_GetDataSize(WindowIden);
}
//*****************************************************************************
//
//! 返回当抢过滤器中是否有过滤出来的数据
//!
//! param: WindowIden 指令窗口指针
//!
//! 
//!
//! return: 返回当过滤数据的字节数；
//
//*****************************************************************************
uint8_t IF_GetDataSize(CmdWindow *WindowIden)
{
    uint8_t DataSize = 0;
    uint8_t ReadIndex = 0;

    //先进行超时判断
    if(WindowIden->WRITE > WindowIden->START && //判断指令过滤器是否在工作
        IF_GET_SYS_TIMER - WindowIden->Timer > IF_TIMEROUT)//判断是否超时
    {//等待数据超时，重置过滤窗口
        //将每个指令的匹配起始地址，设置为写入地址
        ResetTargetInstruction(WindowIden,WindowIden->WRITE);
        //设置过滤窗口的起点。
        WindowIden->START = WindowIden->WRITE;
    }

    // 获取当前数据读取位置
    ReadIndex = WindowIden->READ;
    while(ReadIndex != WindowIden->START)
    {
        ReadIndex = IndexAdd(ReadIndex);
        DataSize++;
    }
    return DataSize;
}
//*****************************************************************************
//
//! 获取过滤后的数据
//!
//! param: WindowIden 指令窗口指针
//!
//! 获取之前，先使用 GetDataSize 函数获取数据个数。
//!
//! return: 获取的数据的值，如果当前没有可获取的数据会返回0;
//
//*****************************************************************************
uint8_t IF_GetData(CmdWindow *WindowIden)
{
    uint8_t ReturnData;
    if(WindowIden->START != WindowIden->READ)
    {
        ReturnData = WindowIden->DataWindow[WindowIden->READ];
        WindowIden->READ = IndexAdd(WindowIden->READ);//指向下一个数据区域
        WindowIden->DataWindowNum--;
        return ReturnData;
    }
    else
    {
        return 0;
    }
}
//*****************************************************************************
//
//! 写数据到指令窗口，在指令响应函数中使用，用于指令回写
//!
//! param: WindowIden 指令窗口指针
//!         Data 要写入的数据
//! 
//!
//! return: 获取的数据的值，如果当前没有可获取的数据会返回0;
//
//*****************************************************************************
void IF_WriteData(CmdWindow *WindowIden, uint8_t Data)
{
    WindowIden->DataWindow[WindowIden->WRITE] = Data;
    WindowIden->WRITE = IndexAdd(WindowIden->WRITE);
    //将每个指令的匹配起始地址，设置为当前指令的起始地址
    ResetTargetInstruction(WindowIden, WindowIden->WRITE);
    //设置过滤窗口的起点。
    WindowIden->START = WindowIden->WRITE;
}
//*****************************************************************************
//
//! 获取上一次指令处理器的接收事件是多少
//!
//! param: WindowIden 指令窗口指针
//!
//! 
//!
//! return: 获取的数据的值，如果当前没有可获取的数据会返回0;
//
//*****************************************************************************
uint32_t IF_GetTimer(CmdWindow *WindowIden)
{
    return WindowIden->Timer;
}
//*****************************************************************************
//
//! 获取当前响应函数的索引号
//!
//! param: WindowIden 指令窗口指针
//!
//! 
//!
//! return: 获取的数据的值，如果当前没有可获取的数据会返回0;
//
//*****************************************************************************
uint16_t IF_GetFunIndex(CmdWindow *WindowIden)
{
    return  WindowIden->Fun;
}
//*****************************************************************************
//
//! 超时处理函数
//!
//! param: WindowIden 指令窗口指针
//!
//! 
//!
//! return: void;
//
//*****************************************************************************
void IF_TimeoutHandler(CmdWindow *WindowIden)
{
    //先进行超时判断
    if(WindowIden->WRITE > WindowIden->START && //判断指令过滤器是否在工作
        IF_GET_SYS_TIMER - WindowIden->Timer > IF_TIMEROUT)//判断是否超时
    {//等待数据超时，重置过滤窗口
        //将每个指令的匹配起始地址，设置为写入地址
        ResetTargetInstruction(WindowIden,WindowIden->WRITE);
        //设置过滤窗口的起点。
        WindowIden->START = WindowIden->WRITE;

        while(IF_GetDataSize(WindowIden) != 0)
        {
            WindowIden->TimoutFun(IF_GetData(WindowIden));
        }
    }
}